home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
SGI Developer Toolbox 6.1
/
SGI Developer Toolbox 6.1 - Disc 4.iso
/
public
/
bit
/
src
/
coledit.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-08-01
|
64KB
|
2,525 lines
/*
* $Id: coledit.c,v 0.91 1994/02/20 00:53:21 zhao Pre-Release $
*
*. This file is part of BIT shareware package. After the two weeks of
* free evaluation period, you are encouraged (required) to register
* your copy for a small registration fee, which is $35 for personal use
* and $50 for commercial, government and institutional use.
*
* Copyright(c) 1993, 1994 by T.C. Zhao.
* All rights reserved.
*
* Permission to use, copy, and distribute this software in its entirety
* for non-commercial purposes is hereby granted, provided that the
* above shareware and copyright notices and this permission notice
* appear in all copies and their documentation.
*
* This software may be modified for your own use, but modified versions
* may not be distributed without prior consent of the author.
*
* This software is provided "as is" without expressed or implied
* warranty of any kind.
*
*.
*
* This file contains
* A. Get the color transformation functions.
* B. Color selection routines.
* C. Color Map editing
*/
#if !defined(lint) && defined(F_ID)
char *id_ced = "$Id: coledit.c,v 0.91 1994/02/20 00:53:21 zhao Pre-Release $";
#endif
#include "bit.h"
#include "extern.h"
/*********************************************************************
* Arbitary one to one transformations
*
*******************************************************************{*/
/******************* Limits and defines *************************/
#define MINPNTS 3 /* min. no. of cntrl pnts */
#define MAXPNTS 34 /* max. no. of cntrl pnts must be even */
/******************* Local variables ****************************/
static float fx[3][MAXPNTS], fy[3][MAXPNTS]; /* the func */
static IPTR saved; /* local image */
static int c0, c1; /* currently active color */
static int changed; /* true if image is modified */
static int reg; /* if apply to a piece of the image */
static int rx, ry, rw, rh; /* region size */
static int lastswap = -1; /* -1 indicate indentity transformation */
static int pswtbl[2][4]; /* pixel swap table */
/* default no. of control points */
static int lastn[3] =
{
9, 9, 9
};
static FL_FORM *coledit; /* main form */
/****************** Local functions *************************/
static void create_form_coledit(void);
static int init_pixtran(IPTR, int);
static void pix2_done(FL_OBJECT *, long);
static void init_func(void);
static void invert_it(void);
static void quant_it(void);
static void band_it(void);
static void detail_it(void);
static void threshold(void);
static void dd_bb(void);
static void pix_replace(void);
static void pix_swap(void);
static void dn_shift(void);
static void up_shift(void);
static void math_exp(void);
/******************************************************************
* Predefined shortcuts
*****************************************************************/
typedef struct
{
const char *l; /* name of the function */
int col; /* color when pressed */
VVfptr f; /* the function itself */
}
shortcut_t;
static shortcut_t sc[] =
{
{"Reset", FL_GREEN, init_func}, /* initialize to identity */
{"Invert", FL_YELLOW, invert_it}, /* photo inversion */
{"Steps", FL_YELLOW, quant_it}, /* step quantization */
{"Band", FL_YELLOW, band_it}, /* band clustering */
{"Threshold", FL_YELLOW, threshold}, /* thresholding */
{"Log(1+ax)", FL_YELLOW, detail_it}, /* intensify weak pixels */
{"Dnshift", FL_YELLOW, dn_shift}, /* shift down 1 bit */
{"Upshift", FL_YELLOW, up_shift}, /* shift up 1 bit */
{"Contrast", FL_YELLOW, dd_bb}, /* dark darker, bright brighter */
{"SwapPix", FL_YELLOW, pix_swap}, /* pixel swap */
{"ChangePix", FL_YELLOW, pix_replace},
{"MathExp", FL_YELLOW, math_exp} /* math expressions */
};
/****************************************************************
* Global entry point
****************************************************************/
int
do_coledit(IPTR im)
{
long dev;
short val;
create_form_coledit();
/* initialize and install window managers resize and reposition events */
init_pixtran(im, 0);
install_wm_handler(init_pixtran);
/* force rectangular region */
set_rubber_obj(RB_RECT);
/* save current image */
free_image(saved);
saved = img_dup(im);
bit_show_form(coledit, FL_PLACE_MOUSE, 0, "ColorEdit");
/* looping until ESC or Done button clicking */
do
{
dev = rubber_info(win_id, &val, &rx, &ry, &rw, &rh, 3, 15);
dev = bit_handle_event(dev, val);
}
while (dev != KEYBD || val != 27);
set_current_window(win_id);
rubber_finish();
bit_hide_form(coledit);
pix2_done(0, 0);
free_image(saved);
getstring_finish();
saved = 0;
return 0;
}
/******* More GUI variavles **********/
static FL_OBJECT *ncounter;
static FL_OBJECT *fcol[3], *tranfg;
static FL_OBJECT *gm, *app[4];
static const char *xl = "Input", *yl = "Output";
/***************************************************************
* Evaluate a math expression given by str.
* The parser uses the fx as variable values and generates the
* corresponding fy.
***************************************************************/
static void
parse_it(const char *str)
{
int j, err;
if (!str || !*str)
return;
fl_freeze_form(coledit);
for (err = 0, j = c0; !err && j < c1; j++)
{
if (!(err = rd_evaluate(str, fx[j], fy[j], lastn[j])))
{
fl_add_xyplot_text(fcol[j], 0.40, 0.92, 0, str, 0,
FL_BLACK, FL_SMALL_FONT, FL_NORMAL_STYLE);
fl_set_xyplot(fcol[j], fx[j], fy[j], lastn[j], "", xl, yl);
}
}
fl_unfreeze_form(coledit);
/* an error has occured. Don't bark */
if (err)
M_err("MathExp", "Error parsing %s", str);
}
/***************************************************************
* Get the math expression and call the parser evaluate it.
***************************************************************/
static void
math_exp(void)
{
set_getstring_cb(parse_it);
getstring("Math Expression", "", 0);
}
/***************************************************************
* do the shortcuts. pix_swap and pix_replace is speical
* in that they are NOT 1-to-1 transformations of color channels,
* but rather PIXEL 1-to-1.
**************************************************************/
/* ARGSUSED */
static void
do_short_cuts(FL_OBJECT * q, long p)
{
VVfptr func = (sc + p)->f;
if (func != pix_swap && func != pix_replace)
lastswap = 0;
/* execute the shortcut function */
func();
}
/*********************************************************
* reset current transformation to null, i.e., y(x) = x
**********************************************************/
static void
init_func(void)
{
int i, j, n;
float *x, *y;
fl_freeze_form(coledit);
for (j = 3; --j >= 0;)
{
n = lastn[j];
for (x = fx[j], y = fy[j], i = 0; i < n; i++)
x[i] = y[i] = (float) i / (n - 1);
fl_clear_xyplot_text(fcol[j]);
fl_set_xyplot(fcol[j], x, y, n, "", xl, yl);
}
/* reset misc. info as well */
fl_set_counter_value(gm, 1.0);
fl_unfreeze_form(coledit);
/* signify identity transformation */
lastswap = -1;
}
/***************************************************************
* if individual control point changes, show the new value and
* also set other channel's value
*****************************************************************/
/* ARGSUSED */
static void
show_it(FL_OBJECT * p, long q)
{
float x, y;
int ix, iy, i, j, n;
char ss[100];
fl_get_active_xyplot(p, &x, &y, &i);
ix = (x * PCMAXV + 0.5);
iy = (y * PCMAXV + 0.5);
sprintf(ss, "(%3d %3d)", ix, iy);
n = lastn[q];
fl_freeze_form(coledit);
fl_add_xyplot_text(p, 0.40, 0.92, 0, ss, 0, FL_BLACK,
FL_SMALL_FONT, FL_NORMAL_STYLE);
for (j = c0; j < c1; j++)
{
if (n != lastn[j])
continue;
if (p != fcol[j])
{
/* clear old text */
fl_clear_xyplot_text(fcol[j]);
fl_set_xyplot_point(fcol[j], x, y, i);
fx[j][i] = x;
fy[j][i] = y;
}
}
lastswap = 0;
fl_unfreeze_form(coledit);
}
/* Color to which transformation applies changes */
/* ARGSUSED */
static void
cind_cb(FL_OBJECT * p, long q)
{
if (q == 3)
{
c0 = 0;
c1 = 3;
}
else
{
c0 = q;
c1 = q + 1;
}
}
/****** insert one point ********/
static void
finer(void)
{
int i, j, ij;
float dx, ddx, *x, *y;
for (j = c0; j < c1; j++)
{
x = fx[j];
y = fy[j];
/* get the max dx and insert a point there */
for (ij = 1, dx = 0.0, i = 1; i < lastn[j]; i++)
{
ddx = x[i] - x[i - 1];
if (dx < ddx)
{
ij = i;
dx = ddx;
}
}
/* do the insertion */
for (i = lastn[j]; i > ij; i--)
{
x[i] = x[i - 1];
y[i] = y[i - 1];
}
x[ij] = (x[ij - 1] + x[ij + 1]) * 0.5;
y[ij] = (y[ij - 1] + y[ij + 1]) * 0.5;
lastn[j] += 1;
}
}
/********* remove one point ************/
static void
coarse(void)
{
int i, j, ij;
float dx, ddx, *x, *y;
for (j = c0; j < c1; j++)
{
x = fx[j];
y = fy[j];
/* get the min dx and delete a point on the right there */
for (ij = 1, dx = 1.0, i = 1; i < lastn[j]; i++)
{
ddx = x[i] - x[i - 1];
if (dx > ddx)
{
ij = i;
dx = ddx;
}
}
/* do the deletion. take care not to delete last point */
if (ij == lastn[j] - 1)
{
x[ij - 1] = x[ij];
y[ij - 1] = y[ij];
}
lastn[j] -= 1;
for (i = ij; i < lastn[j]; i++)
{
x[i] = x[i + 1];
y[i] = y[i + 1];
}
}
}
/************* add points ****************/
/* ARGSUSED */
static void
pnts_cb(FL_OBJECT * p, long q)
{
int i, j, cn;
int n = (fl_get_counter_value(p) + 0.5);
for (j = c0; j < c1; j++)
{
cn = lastn[j]; /* must save no. of points. */
if (n > lastn[j])
{ /* add */
for (i = 0; i < n - cn; i++)
finer();
}
else
{
for (i = 0; i < cn - n; i++)
coarse();
}
fl_set_xyplot(fcol[j], fx[j], fy[j], lastn[j], "", xl, yl);
}
}
/****************************************************************
* Check if the transformation is be applied to a (rectabgular)
* region of the image and if so, return the subimage
****************************************************************/
static void *
check_if_region(void)
{
void *pp = 0;
/* check if the transformation is to be applied to a region */
reg = (rx - imgptr->xi) || (ry - imgptr->yi) ||
(rw - imgptr->w) || (rh - imgptr->h);
/*
* if transformation is requested for a region, need to get the image for
* the requested region and convert image to RGB
*/
if (reg)
{
if (IS_CI(imgptr))
{
show_busy("Converting to RGB ...");
(void) img_convert_type(imgptr, T_RGBA);
imgptr->io->display(imgptr, 0, 0);
}
if (!(pp = get_subimage(imgptr, rx, ry, rw, rh)))
{
Bark("ColEdit_Region", "Unable to get submatrix");
}
}
return pp;
}
/****************************************************************
* Do the pixel swapping (latswap == 2) and replace (lastswap==1)
* In case the transformation is to be applied to a region,
* pp would contain the subimage
*****************************************************************/
static void
swap_pixels(void **pp)
{
long total = rw * rh;
if (reg && pp)
{
modify_cpack_pixel(pp[0], total,
Pack(pswtbl[0][0], pswtbl[0][1], pswtbl[0][2]),
Pack(pswtbl[1][0], pswtbl[1][1], pswtbl[1][2]),
lastswap == 2);
put_subimage(imgptr, pp, make_rect(rx, ry, rw, rh), 1);
set_current_window(win_id);
Rectwrite(rx, ry, rx + rw - 1, ry + rh - 1, pp[0]);
free_mat(pp);
}
else
{
img_modify_pixel(imgptr, pswtbl[0], pswtbl[1], lastswap == 2);
imgptr->io->display(imgptr, 2, 0);
}
}
/*******************************************************************
* Do the general transformations: rgb contains the normalized
* tranformation functions
*******************************************************************/
static void
do_gen_tran(void **pp, pc_t rgb[][PCMAX])
{
if (!reg)
{ /* transformation applies to entire image */
if (IS_CPACK(imgptr))
{
modify_rgb(imgptr->raster, imgptr->w * imgptr->h, rgb[0],
rgb[1], rgb[2]);
}
else
{
modify_cmap(imgptr->cmap, rgb[0], rgb[1], rgb[2]);
}
imgptr->io->display(imgptr, 1, 0);
}
else
{ /* to a specific region */
modify_rgb(pp[0], rh * rw, rgb[0], rgb[1], rgb[2]);
put_subimage(imgptr, pp, make_rect(rx, ry, rw, rh), 1);
set_current_window(win_id);
Rectwrite(rx, ry, rx + rw - 1, ry + rh - 1, pp[0]);
free_mat(pp);
}
}
/***************************************************************
* interpolate and normalize the transformation (x,y) from (0,1)
* to (0, PCMAXV)
***************************************************************/
static void
normalize_func(float *x, float *y, int n, pc_t *norm)
{
int i, k;
float xx, yy;
for (i = 0; i < PCMAX; i++)
{
xx = (double) i / PCMAXV;
k = b_search(x, n, xx);
if ((x[k + 1] - x[k]) > 1.e-5)
yy = y[k] + (y[k + 1] - y[k]) / (x[k + 1] - x[k])
* (xx - x[k]);
else
yy = (y[k] + y[k + 1]) * 0.5;
/* force to within (0,1) */
Range(yy, 0.0, 1.0);
norm[i] = (yy * PCMAXV + 0.5);
}
}
/******************************************************************
* apply the transformation defined by fx, fy
******************************************************************/
/* ARGSUSED */
static void
apply_func(FL_OBJECT * p, long q)
{
int j;
pc_t rgb[3][PCMAX];
void *pp = 0;
long owin = winget();
if (lastswap == -1) /* identity transformation */
return;
/* at this point, all changes made so far becomes permanent */
free_image(saved);
saved = img_dup(imgptr);
changed = 1;
pp = check_if_region();
/*
* if swap/replace pixels, need special handling 'cause the seperated RGB
* transformation can't do it
*/
show_busy("Transforming ...");
if (lastswap)
{ /* fake */
swap_pixels(pp);
}
else
{
/* general transformation * */
for (j = 0; j < 3; j++)
{
fl_get_xyplot(fcol[j], fx[j], fy[j], lastn + j);
normalize_func(fx[j], fy[j], lastn[j], rgb[j]);
}
do_gen_tran(pp, rgb);
}
end_busy();
set_current_window(owin);
}
/****************************************************
* generate the gamma table
****************************************************/
#include <math.h>
/* ARGSUSED */
static void
gamma_cb(FL_OBJECT * p, long q)
{
int i, j;
float cgamma = fl_get_counter_value(p);
fl_freeze_form(coledit);
for (j = c0; j < c1; j++)
{
for (i = 0; i < lastn[j]; i++)
{
fx[j][i] = (float) i / (lastn[j] - 1);
fy[j][i] = pow(fx[j][i], cgamma);
}
fl_set_xyplot(fcol[j], fx[j], fy[j], lastn[j], "", xl, yl);
fl_set_xyplot_text(fcol[j], 0.8, 0.92, 0, ftoa(cgamma, 2),
0, FL_BLACK, FL_SMALL_FONT, FL_NORMAL_STYLE);
}
fl_unfreeze_form(coledit);
lastswap = 0;
}
/****************************************************************
* photo-inversion function
*****************************************************************/
static void
invert_it(void)
{
int i, j;
for (j = c0; j < c1; j++)
{
fl_get_xyplot(fcol[j], fx[j], fy[j], &lastn[j]);
for (i = 0; i < lastn[j]; i++)
{
fy[j][i] = 1.0 - fy[j][i];
}
fl_set_xyplot(fcol[j], fx[j], fy[j], lastn[j], "", xl, yl);
}
}
/****************************************************************
* pixels clustering
*****************************************************************/
static void
quant_it(void)
{
int i, j, n;
double dx, dy, ddx = 1.0 / PCMAXV;
for (j = c0; j < c1; j++)
{
/* need to be even number of points */
lastn[j] += (lastn[j] % 2);
fl_set_counter_value(ncounter, lastn[j]);
/* divide into segments of half of no. of points */
n = lastn[j] / 2;
dx = 1.0 / n;
dy = 1.0 / (n - 1);
fx[j][0] = fy[j][0] = 0.0;
fx[j][lastn[j] - 1] = fy[j][lastn[j] - 1] = 1.0;
for (i = 1; i < lastn[j] - 2; i += 2)
{
fx[j][i] = fx[j][i - 1] + dx - ddx;
fy[j][i] = fy[j][i - 1];
fx[j][i + 1] = fx[j][i] + ddx + ddx;
fy[j][i + 1] = fy[j][i] + dy;
}
fl_set_xyplot(fcol[j], fx[j], fy[j], lastn[j], "", xl, yl);
}
}
/*******************************************************
* Thresholding function
********************************************************/
static void
threshold(void)
{
int j, done;
static int th = 126;
double ddx = 1.0 / PCMAXV;
for (j = c0; j < c1; j++)
lastn[j] = 4;
quant_it();
do
{
for (j = c0; j < c1; j++)
{
fx[j][1] = (float) th / PCMAXV;
fx[j][2] = fx[j][1] + ddx;
fl_set_xyplot(fcol[j], fx[j], fy[j], lastn[j], "", xl, yl);
}
done = getint("Enter Threshold", &th, 1, 254, 1);
}
while (!done);
/* final functions */
for (j = c0; j < c1; j++)
{
fx[j][1] = (float) th / PCMAXV;
fx[j][2] = fx[j][1] + ddx;
fl_set_xyplot(fcol[j], fx[j], fy[j], lastn[j], "", xl, yl);
}
}
/**************************************************************
* setting clusters of pixels to zero, sort of like contour
***************************************************************/
static void
band_it(void)
{
int i, j, n;
double dx, dy, ddx = 1.0 / PCMAXV, yy;
/*
* divide the region into segments with alternating zeros. there must be
* gurantee that the no. of points is multple of 4 and minimum is 8. (4
* points band is the same as two step)
*/
for (j = c0; j < c1; j++)
{
fl_get_xyplot(fcol[j], fx[j], fy[j], &lastn[j]);
lastn[j] = 4 * (lastn[j] / 4);
if (lastn[j] < 8)
lastn[j] = 8;
fl_set_counter_value(ncounter, lastn[j]);
/* no. of periods */
n = lastn[j] / 4;
dx = 1.0 / (2.0 * n);
dy = 1.0 / n;
/* the stuff within the loop is exactly one period */
yy = 0.0;
for (i = 0; i < lastn[j] - 3; i += 4)
{
fx[j][i] = dx * (i / 2);
fy[j][i] = 0.0;
fx[j][i + 1] = fx[j][i] + dx;
fy[j][i + 1] = 0.0;
fx[j][i + 2] = fx[j][i + 1] + ddx;
fy[j][i + 2] = (yy += dy);
fx[j][i + 3] = fx[j][i + 2] + dx - 2.0 * ddx;
fy[j][i + 3] = yy;
}
fx[j][lastn[j] - 1] = 1.0;
fl_set_xyplot(fcol[j], fx[j], fy[j], lastn[j], "", xl, yl);
}
}
/*******************************************************************
* This function shows the approximate transformation function,
* but it really does not do anything useful since replace and swap are
* handled seperately by table pswtbl, not by reading and digitizing
* the functions
*********************************************************************/
static void
fake_1(float *x, float *y, int n, int from, int to)
{
int i;
i = b_search(x, n, (float) from / PCMAXV);
if (i == 0)
{
x[i] = (float) from / PCMAXV;
y[i] = (float) to / PCMAXV;
x[i + 1] = (float) (from + 0.9) / PCMAXV;
y[i + 1] = x[i + 1];
}
else
{
x[i] = (float) from / PCMAXV;
y[i] = (float) to / PCMAXV;
x[i - 1] = (float) (from - 0.9) / PCMAXV;
y[i - 1] = x[i - 1];
if (i < n - 1)
{
x[i + 1] = (float) (from + 0.9) / PCMAXV;
y[i + 1] = x[i - 1];
}
}
}
/**********************************************/
static void
fake_func(int sw)
{
int i, j;
/* 8 or 9 points should be enough, even for swapping */
if (lastn[0] < 9)
lastn[0] = lastn[1] = lastn[2] = 9;
/* initialize to identity transformation */
for (j = 0; j < 3; j++)
{
for (i = 0; i < lastn[j]; i++)
fx[j][i] = fy[j][i] = (float) i / (lastn[j] - 1);
}
/* check to see if operation is an identity */
for (i = j = 0; !j && i < 3; i++)
j = (pswtbl[0][i] - pswtbl[1][i]);
if (!j)
return;
fl_clear_xyplot_text(fcol[0]);
fl_clear_xyplot_text(fcol[1]);
fl_clear_xyplot_text(fcol[2]);
fl_freeze_form(coledit);
/* generate the function */
fl_add_xyplot_text(fcol[0], 0.6, 0.92, 0, sw ? "SwapPix" : "ChangePix",
0, FL_BLACK, FL_SMALL_FONT, FL_NORMAL_STYLE);
for (j = 0; j < 3; j++)
{
fake_1(fx[j], fy[j], lastn[j], pswtbl[0][j], pswtbl[1][j]);
if (sw)
fake_1(fx[j], fy[j], lastn[j], pswtbl[1][j], pswtbl[0][j]);
fl_set_xyplot_only(fcol[j], fx[j], fy[j], lastn[j], "", xl, yl);
}
fl_set_counter_value(ncounter, Max(lastn[0], lastn[2]));
fl_unfreeze_form(coledit);
}
/******************************************************************
* Pixel transformation routines
******************************************************************/
static void show_pix2(int);
static void
pix_swap(void)
{
lastswap = 2;
show_pix2(1);
}
static void
pix_replace(void)
{
lastswap = 1;
show_pix2(0);
}
static void
shift_it(int dir)
{
int i, j, iy;
for (j = c0; j < c1; j++)
{
fl_get_xyplot(fcol[j], fx[j], fy[j], &lastn[j]);
for (i = 0; i < lastn[j]; i++)
{
iy = (fy[j][i] * (PCMAX - 1) + 0.5);
iy = (dir > 0 ? (iy << 1) : (iy >> 1));
iy &= PCMAX - 1;
fy[j][i] = (float) iy / (PCMAX - 1);
}
fl_set_xyplot(fcol[j], fx[j], fy[j], lastn[j], "", xl, yl);
}
}
static void
dn_shift(void)
{
shift_it(-1);
}
static void
up_shift(void)
{
shift_it(1);
}
/* do a f(x) = log(1.0+ scale * x)/log(scale + 1) */
static void
detail_it(void)
{
int i, j;
static float dscale = 5.0;
double factor;
int done;
do
{
factor = 1.0 / log10(1.0 + dscale);
for (j = c0; j < c1; j++)
{
for (i = 0; i < lastn[j]; i++)
{
fy[j][i] = log10(dscale * fx[j][i] + 1.0) * factor;
}
fl_set_xyplot(fcol[j], fx[j], fy[j], lastn[j], "", xl, yl);
}
done = getfloat("Enter Scale factor:", &dscale, 1.0, 100.0, 1, 1);
}
while (!done);
}
/*************************************************************
* Dark darker, bright brighter
*
* To get the correct curvature, we need to invert the
* following function and the inversion is not unique or
* out of the real domain, do it numerically, taking advantage
* of the fact the inversion is just a mirror at y = x
**************************************************************/
#define F(x) (0.5 * ( 1.0 + pow(2.0*(x)-1,3.0)))
static void
dd_bb(void)
{
int i, j;
for (j = c0; j < c1; j++)
{
for (i = 0; i < lastn[j]; i++)
{
fy[j][i] = (float) i / (lastn[j] - 1);
fx[j][i] = F(fy[j][i]);
}
fl_set_xyplot(fcol[j], fx[j], fy[j], lastn[j], "", xl, yl);
}
}
/* brightness of the image */
static int bpercent = 1;
/* ARGSUSED */
static void
bset_cb(FL_OBJECT * q, long p)
{
bpercent = !bpercent;
fl_set_object_label(q, bpercent ? "Brightness(%)" : "Brightness(Abs)");
}
/* ARGSUSED */
static void
brightness_cb(FL_OBJECT * q, long p)
{
int i, j;
float delta = 0.01;
float *x, *y;
delta = 0.01 * p;
for (j = c0; j < c1; j++)
{
x = fx[j];
y = fy[j];
fl_get_xyplot(fcol[j], x, y, &lastn[j]);
if (bpercent)
{ /* percentge */
for (i = 0; i < lastn[j]; i++)
{
y[i] *= (1.0 + delta);
if (y[i] > 1.0)
y[i] = 1.0;
}
}
else
{ /* abslute change */
for (i = 0; i < lastn[j]; i++)
{
y[i] += delta;
if (y[i] < 0.0)
y[i] = 0.0;
else if (y[i] > 1.0)
y[i] = 1.0;
}
}
fl_set_xyplot(fcol[j], x, y, lastn[j], "", xl, yl);
fl_set_xyplot_ybounds(fcol[j], 0.0, 1.0);
}
lastswap = 0;
}
/*ARGSUSED*/
static int
init_pixtran(IPTR im, int wme)
{
static int irx, iry;
set_rubber_bounds(1, im->xi, im->yi, im->w, im->h);
if (wme)
{
rx += im->xi - irx;
ry += im->yi - iry;
}
else
{
rw = im->w;
rh = im->h;
rx = im->xi;
ry = im->yi;
}
irx = im->xi;
iry = im->yi;
return 0;
}
/* ARGSUSED */
static void
undo_cb(FL_OBJECT * q, long p)
{
if (!changed)
return;
free_image(imgptr);
imgptr = img_dup(saved);
imgptr->io->display(imgptr, 0, 0);
end_busy();
changed = 0;
}
/* done */
/* ARGSUSED */
static void
finish_coledit(FL_OBJECT * p, long q)
{
remove_wm_handler(init_pixtran);
fl_qenter(KEYBD, 27);
}
static void
create_form_coledit(void)
{
FL_OBJECT *obj;
int i, totalsc = sizeof(sc) / sizeof(sc[0]);
float y, dy, x, dx;
static int ok;
if (ok)
return;
coledit = fl_bgn_form(FL_NO_BOX, 380.0, 470.0);
obj = fl_add_box(FL_UP_BOX, 0.0, 0.0, 380.0, 470.0, "");
fl_set_object_color(obj, 9, 47);
fl_set_object_align(obj, FL_ALIGN_TOP);
obj = fl_add_button(FL_HIDDEN_BUTTON, 0, 0, 380, 470, "");
fl_set_call_back(obj, help_cb, HELP_COLEDIT);
/* transformation functions */
tranfg = fl_bgn_group();
y = 310;
dy = 150;
for (i = 0; i < 3; i++, y -= dy)
{
fcol[i] = fl_add_xyplot(FL_ACTIVE_XYPLOT, 10.0, y, 170.0, dy, "");
fl_set_xyplot_xscale(fcol[i], 0, 0);
fl_set_xyplot_yscale(fcol[i], 0, 0);
fl_set_xyplot_return(fcol[i], 1);
fl_set_object_color(fcol[i], 9, 9);
fl_set_xyplot_autobounds(fcol[i], 0, 0);
fl_set_xyplot_xbounds(fcol[i], 0.0, 1.0);
fl_set_xyplot_ybounds(fcol[i], 0.0, 1.0);
fl_set_call_back(fcol[i], show_it, i);
}
fl_set_xyplot_colors(fcol[0], FL_RED, 0);
fl_set_xyplot_colors(fcol[1], FL_GREEN, 0);
fl_set_xyplot_colors(fcol[2], FL_BLUE, 0);
fl_end_group();
/* gamma */
gm = fl_add_counter(FL_NORMAL_COUNTER, 200.0, 90.0, 160.0, 25.0, "Gamma");
fl_set_object_lsize(gm, 10.0);
fl_set_object_align(gm, FL_ALIGN_TOP);
fl_set_counter_precision(gm, 2);
fl_set_counter_bounds(gm, 0.001, 10);
fl_set_counter_step(gm, 0.05, 0.20);
fl_set_counter_value(gm, 1.0);
fl_set_counter_return(gm, 1);
fl_set_call_back(gm, gamma_cb, 0);
/* brightness */
obj = fl_add_button(FL_TOUCH_BUTTON, 210.0, 40.0, 25.0, 25.0, "<<");
fl_set_object_boxtype(obj, FL_FRAME_BOX);
fl_set_object_color(obj, 47, 12);
fl_set_call_back(obj, brightness_cb, -3);
obj = fl_add_button(FL_TOUCH_BUTTON, 235.0, 40.0, 25.0, 25.0, "<");
fl_set_object_boxtype(obj, FL_FRAME_BOX);
fl_set_object_color(obj, 47, 12);
fl_set_call_back(obj, brightness_cb, -1);
obj = fl_add_button(FL_TOUCH_BUTTON, 330.0, 40.0, 25.0, 25.0, ">>");
fl_set_object_boxtype(obj, FL_FRAME_BOX);
fl_set_object_color(obj, 47, 12);
fl_set_call_back(obj, brightness_cb, 3);
obj = fl_add_button(FL_TOUCH_BUTTON, 305.0, 40.0, 25.0, 25.0, ">");
fl_set_object_boxtype(obj, FL_FRAME_BOX);
fl_set_object_color(obj, 47, 12);
fl_set_call_back(obj, brightness_cb, 1);
obj = fl_add_button(FL_NB, 230.0, 65.0, 110.0, 20.0, "");
fl_set_object_label(obj, bpercent ? "Brightness(%)" : "Brightness(Abs)");
fl_set_object_boxtype(obj, FL_FLAT_BOX);
fl_set_object_lsize(obj, 10.0);
fl_set_object_color(obj, 9, 9);
fl_set_call_back(obj, bset_cb, 0);
/* color apply group */
fl_bgn_group();
app[0] = obj = fl_add_roundbutton(FL_RB, 195.0, 430.0, 30.0, 30.0, "Red");
fl_set_object_color(obj, 7, 1);
fl_set_object_lsize(obj, 10.0);
fl_set_call_back(obj, cind_cb, 0);
app[1] = obj = fl_add_roundbutton(FL_RB, 250.0, 430.0, 30.0, 30.0, "Green");
fl_set_object_color(obj, 7, 2);
fl_set_object_lsize(obj, 10.0);
fl_set_call_back(obj, cind_cb, 1);
app[2] = obj = fl_add_roundbutton(FL_RB, 320.0, 430.0, 30.0, 30.0, "Blue");
fl_set_object_color(obj, 7, 4);
fl_set_object_lsize(obj, 10.0);
fl_set_call_back(obj, cind_cb, 2);
app[3] = obj = fl_add_button(FL_RB, 235.0, 405.0, 115.0, 25.0, "RGB");
fl_set_object_lsize(obj, 10.0);
fl_set_object_color(obj, FL_MAGIC1, FL_MAGIC2);
fl_set_call_back(obj, cind_cb, 3);
c0 = 0;
c1 = 3;
fl_set_button(obj, 1);
fl_end_group();
ncounter = obj = fl_add_counter(FL_NC, 210.0, 360.0, 160.0, 25.0,
"Control Points");
fl_set_object_lsize(obj, 10.0);
fl_set_object_align(obj, FL_ALIGN_TOP);
fl_set_counter_precision(obj, 0);
fl_set_counter_bounds(obj, MINPNTS, MAXPNTS);
fl_set_counter_step(obj, 1, 2);
fl_set_counter_value(obj, lastn[0]);
fl_set_counter_return(obj, 1);
fl_set_call_back(obj, pnts_cb, 0);
/* misc control */
obj = fl_add_button(FL_NORMAL_BUTTON, 280.0, 145.0, 80.0, 25.0, "Apply");
fl_set_object_color(obj, 47, 3);
fl_set_object_lsize(obj, 10.00);
fl_set_call_back(obj, apply_func, 0);
obj = fl_add_button(FL_NORMAL_BUTTON, 200.0, 145.0, 80.0, 25.0, "Undo");
fl_set_object_color(obj, FL_MAGIC1, FL_GREEN);
fl_set_object_lsize(obj, 10.0);
fl_set_call_back(obj, undo_cb, 0);
obj = fl_add_button(FL_NORMAL_BUTTON, 310.0, 10.0, 60.0, 25.0, "Done");
fl_set_object_lsize(obj, 10.0);
fl_set_object_color(obj, FL_MAGIC1, FL_YELLOW);
fl_set_call_back(obj, finish_coledit, 0);
/* short cuts */
y = 320.0;
x = 200.0;
for (dx = 80, dy = 25, i = 0; i < totalsc; i += 2, y -= dy)
{
obj = fl_add_button(FL_NB, x, y, dx, dy, sc[i].l);
fl_set_object_lsize(obj, 10.0);
fl_set_object_color(obj, FL_MAGIC1, sc[i].col);
fl_set_call_back(obj, do_short_cuts, i);
if (i + 1 < totalsc)
{
obj = fl_add_button(FL_NB, x + dx + 5, y, dx, dy, sc[i + 1].l);
fl_set_object_lsize(obj, 10.0);
fl_set_object_color(obj, FL_MAGIC1, sc[i + 1].col);
fl_set_call_back(obj, do_short_cuts, i + 1);
}
}
fl_end_form();
ok = 1;
init_func();
}
/*******************************************************************
* Pixel Swap and Pixel Change Routines
*
******************************************************************/
static FL_FORM *pix2; /* pixel swap/replace form */
static FL_OBJECT *plab[2], *colbox[2];
static void create_form_pix2(void);
/* showing the swap/change colors: FORM index */
static int pcind[2] =
{
1038, 1039
};
/************************************************************
* present the colors in pixelswap in RGB components and
* also redraw the colorbox showing the packed color
*******************************************************/
static int whichC;
static void
show_label(int ccc[])
{
char pt[100];
sprintf(pt, "(%d,%d,%d)", ccc[0], ccc[1], ccc[2]);
fl_freeze_form(pix2);
fl_set_object_label(plab[whichC], pt);
fl_mapcolor(pcind[whichC], ccc[0], ccc[1], ccc[2]);
fl_redraw_object(colbox[whichC]);
fl_unfreeze_form(pix2);
fake_func(lastswap - 1);
}
/******** Set either the target or new pix *********/
/*ARGSUSED*/
static void
setpix(FL_OBJECT * q, long p)
{
whichC = p;
set_getcolor_cb(show_label);
get_color(imgptr, pswtbl[p], 0);
}
/********* Targe/new pixels are selected *********/
/*ARGSUSED*/
static void
pix2_done(FL_OBJECT * p, long q)
{
if (pix2 && pix2->visible)
{
hide_getcolor();
bit_hide_form(pix2);
fake_func(lastswap - 1);
}
}
static FL_OBJECT *bi;
static void
show_pix2(int sw)
{
create_form_pix2();
(sw ? fl_show_object : fl_hide_object) (bi);
bit_show_form(pix2, FL_PLACE_SIZE, 0, "Pixel2");
}
static void
create_form_pix2(void)
{
FL_OBJECT *obj;
static int pix2form;
if (pix2form)
return;
pix2 = fl_bgn_form(FL_NO_BOX, 310.0, 170.0);
obj = fl_add_box(FL_UP_BOX, 0.0, 0.0, 310.0, 170.0, "");
obj = fl_add_button(FL_NB, 15.0, 120.0, 85.0, 30.0, "SetTarget");
fl_set_object_lsize(obj, 10.0);
fl_set_call_back(obj, setpix, 0);
obj = fl_add_button(FL_NB, 15.0, 50.0, 85.0, 30.0, "SetNewPix");
fl_set_object_lsize(obj, 10.0);
fl_set_call_back(obj, setpix, 1);
colbox[0] = obj = fl_add_box(FL_DOWN_BOX, 220.0, 120.0, 80.0, 30.0, "");
fl_mapcolor(pcind[0], pswtbl[0][0], pswtbl[0][1], pswtbl[0][2]);
fl_set_object_color(obj, pcind[0], 0);
colbox[1] = obj = fl_add_box(FL_DOWN_BOX, 220.0, 50.0, 80.0, 30.0, "");
fl_mapcolor(pcind[1], pswtbl[1][0], pswtbl[1][1], pswtbl[1][2]);
fl_set_object_color(obj, pcind[1], 0);
plab[0] = obj = fl_add_text(FL_NT, 110.0, 120.0, 100.0, 30.0, "");
fl_set_object_boxtype(obj, FL_BORDER_BOX);
fl_set_object_lsize(obj, 10.0);
fl_set_object_align(obj, FL_ALIGN_CENTER);
fl_set_object_lstyle(obj, FL_BOLD_STYLE);
plab[1] = obj = fl_add_text(FL_NT, 110.0, 50.0, 100.0, 30.0, "");
fl_set_object_boxtype(obj, FL_BORDER_BOX);
fl_set_object_lsize(obj, 10.0);
fl_set_object_align(obj, FL_ALIGN_CENTER);
fl_set_object_lstyle(obj, FL_BOLD_STYLE);
obj = fl_add_button(FL_RETURN_BUTTON, 120.0, 10.0, 80.0, 30.0, "OK");
fl_set_object_color(obj, 47, 2);
fl_set_object_lsize(obj, 10.0);
fl_set_call_back(obj, pix2_done, 0);
obj = fl_add_box(FL_FLAT_BOX, 110.0, 80.0, 40.0, 40.0, "@2");
fl_set_object_lcol(obj, 4);
bi = obj = fl_add_box(FL_FLAT_BOX, 160.0, 80.0, 40.0, 40.0, "@8");
fl_set_object_lcol(obj, 4);
fl_end_form();
pix2form = 1;
show_label(pswtbl[whichC = 0]);
show_label(pswtbl[whichC = 1]);
}
/************************************End of 1 to 1 ***** }*/
/*---- call back routines when there is color change ----*/
static Getcolor_cb color_cb, rgbcolor_cb, cmapcolor_cb;
static GLQhandler color_glcb, rgbcolor_glcb, cmapcolor_glcb;
/* alter the current color */
static void (*set_current_color) (int[]);
/**************** local functions ******************************/
static void create_the_forms(void);
static void hide_rgb_form(void);
static void hide_cmap_form(void);
static void set_rgbcolor(int[]);
static void set_cmapcolor(int[]);
/*******************************************************************
* the global routines that get called to handle color selection
*
* get_color
* hide_getcolor
* set_getcolor_cb
* set_getcolor_glcb
* set_getcolor
*
* All routines are image type blind
****************************************************************{*/
/*******************************************************
* Global entry
******************************************************/
int
get_color(IPTR im, int col[], int block)
{
int status;
create_the_forms();
if (IS_CI(im))
{
int ci;
/* default handlers */
cmapcolor_cb = color_cb;
cmapcolor_glcb = color_glcb;
status = get_cmapcolor(im, col, block);
ci = col[3];
col[0] = im->cmap->ct[0][ci];
col[1] = im->cmap->ct[1][ci];
col[2] = im->cmap->ct[2][ci];
}
else
{
/* default handlers */
rgbcolor_cb = color_cb;
rgbcolor_glcb = color_glcb;
status = get_RGBcolor(im, col, block);
col[3] = 0;
}
/* remove the handlers */
color_cb = 0;
color_glcb = 0;
set_current_color = 0;
return status;
}
/* remove the get color control panel */
void
hide_getcolor(void)
{
create_the_forms();
hide_rgb_form();
hide_cmap_form();
}
/* alter whatever is selected in the color selection panel */
void
set_getcolor(int c[])
{
if (set_current_color)
set_current_color(c);
}
/****************************************************************
* function to handle color changes
****************************************************************/
void
set_getcolor_cb(Getcolor_cb cb)
{
color_cb = cb;
}
/******************************************************************
* functions to handle Q events. Not impleneted and untested
******************************************************************/
void
set_getcolor_glcb(GLQhandler cb)
{
color_glcb = cb;
}
/********************************************************************
*
* END OF color selection
*******************************************************************}*/
/********************************************************************
* Select a particular color in RGB
****************************************************************{*/
/*-------- local functions ----------------------- */
static void slider_cb(FL_OBJECT *, long);
static void create_the_forms(void);
/*---------local variables -------------------------*/
static int rgbcol[4]; /* buffer, used on cancel */
static int *ccrgb; /* arrays as passed to get_RGBcolor */
/* GUI variables */
static FL_FORM *rgb_form;
static FL_FORM *predefc; /* forms for PreDefinedColors */
static FL_OBJECT *ok_butt, *slider[3], *cancel;
static FL_OBJECT *pcc;
static int rgb_border = 1;
/* to avoid interference with window manager or bit program
* use something large as the button colors
*/
#define OK_I (MAXCML + 10)
#define CAN_I (MAXCML + 11)
/**************************************************************
* Change the RGB color. All RGB color setting for the mixer
* Must go thru this
*************************************************************/
static void
set_rgb_slider(int s1, int s2, int s3)
{
int cr, cg, cb;
fl_freeze_form(rgb_form);
/* getting a slider is much faster than setting a slider */
cr = fl_get_slider_value(slider[0]);
cg = fl_get_slider_value(slider[1]);
cb = fl_get_slider_value(slider[2]);
/* change only the sliders that need to be changed */
if (cr - s1)
fl_set_slider_value(slider[0], s1);
if (cg - s2)
fl_set_slider_value(slider[1], s2);
if (cb - s3)
fl_set_slider_value(slider[2], s3);
/* show current selection */
fl_mapcolor(OK_I, s1, s2, s3);
fl_redraw_object(ok_butt);
fl_unfreeze_form(rgb_form);
/* cache and also taking care of input ccrgb is an alias */
if (ccrgb)
{
ccrgb[0] = s1;
ccrgb[1] = s2;
ccrgb[2] = s3;
}
}
static int namedcolor; /* if current color is named */
/* invoked by set_getcolor */
static void
set_rgbcolor(int c[])
{
set_rgb_slider(c[0], c[1], c[2]);
/* color setting invalidates predefined color names */
if (namedcolor)
{
fl_deselect_browser(pcc);
namedcolor = 0;
}
/* also need to service the color change */
if (rgbcolor_cb)
rgbcolor_cb(c);
}
/* draw the cancel button as the input color */
static void
draw_rgb_cancel(int col[])
{
fl_mapcolor(CAN_I, col[0], col[1], col[2]);
fl_redraw_object(cancel);
}
/**********************************************************
* Handle GL events that occur. If the events are known
* and handled, return 0, else return the input event
*********************************************************/
/***********************************************
* How to pick a screen pixel as current color
**********************************************/
/*ARGSUSED*/
static long
rgb_pick_pix(long dev, short val)
{
int xx, yy, lxx = -1, lyy = -1;
rgba_t pixel;
int rgb[3];
do
{
/* get mouse position relative to window */
WHERE_R2W(xx, yy, win_xo, win_yo);
if (xx != lxx || yy != lyy)
{
lxx = xx;
lyy = yy;
show_mouse_position(xx, yy);
lrectread(xx, yy, xx, yy, &pixel);
Unpack(pixel, rgb[0], rgb[1], rgb[2]);
set_rgbcolor(rgb);
slider_cb(0, 0);
}
}
while (control_down && mouse_down);
fl_qreset();
return 0;
}
/**************************************************
* GL event handler while doing color mixing
**************************************************/
static long
rgb_fl_event(long dev, short val)
{
long cq = dev;
/* if not meant for this routine,return the event */
if (!rgb_form || !rgb_form->visible)
return dev;
switch (dev)
{
case LEFTMOUSE:
case MIDDLEMOUSE:
if (val && control_down)
{
cq = rgb_pick_pix(dev, val);
}
break;
case LEFTCTRLKEY:
case RIGHTCTRLKEY:
if (val)
{
set_cursor(win_id, CUR_S_CROSS);
do
{
if (getbutton(LEFTMOUSE))
cq = rgb_pick_pix(dev, val);
}
while (control_down);
/* control is released, reset cursor */
reset_cursor(win_id);
cq = 0;
}
break;
}
if (cq) /* still not consumed */
cq = rgbcolor_glcb ? rgbcolor_glcb(dev, val) : dev;
return cq;
}
/***************************************************************
* Gloabl entry point for selecting RGB color
*
****************************************************************/
/*ARGSUSED*/
int
get_RGBcolor(IPTR im, int col[], int block)
{
int place = block ? FL_PLACE_MOUSE : FL_PLACE_SIZE;
create_the_forms();
set_current_color = set_rgbcolor;
ccrgb = col;
set_rgb_slider(col[0], col[1], col[2]);
/* make a copy, which will be the cancel color */
rgbcol[0] = col[0];
rgbcol[1] = col[1];
rgbcol[2] = col[2];
draw_rgb_cancel(rgbcol);
if (!rgb_form->visible)
{
/* how to handle Q events */
install_GLQ_handler(rgb_fl_event);
}
if (block)
fl_deactivate_all_forms();
bit_show_form(rgb_form, place, rgb_border, "RGBColor");
set_cursor(rgb_form->window, CUR_HAND);
if (block)
{
/* eat every Q events except rgb_fl_event */
int rgbfinish;
short val;
do
{
rgbfinish = (fl_do_forms() == FL_EVENT) &&
(bit_qread(&val) == F1KEY && val == 100);
}
while (!rgbfinish);
fl_activate_all_forms();
}
return 0;
}
/***********************************************************
* Remove the mixer and its friends when OK is pressed
***********************************************************/
/* ARGSUSED */
static void
ok_cb(FL_OBJECT * ob, long q)
{
reset_cursor(win_id);
fl_activate_all_forms();
/* reset all call back functions */
rgbcolor_cb = 0;
rgbcolor_glcb = 0;
remove_GLQ_handler(rgb_fl_event);
bit_hide_form(rgb_form);
bit_hide_form(predefc);
/* secrete terminating key */
qenter(F1KEY, 100);
}
static void
hide_rgb_form(void)
{
create_the_forms();
if (rgb_form->visible)
ok_cb(0, 0);
}
/****************************************************************
* if cancel is pressed
*****************************************************************/
/*ARGSUSED*/
static void
cancel_cb(FL_OBJECT * ob, long q)
{
set_rgb_slider(rgbcol[0], rgbcol[1], rgbcol[2]);
/* redraw OK button etc. and re-read slider and service color change */
slider_cb(0, 0);
}
/******************************************************************
* If there is any change in slider this routine be called
* It might also be called by other rouines (which calls
* with p == 0
*******************************************************************/
/* ARGSUSED */
static void
slider_cb(FL_OBJECT * p, long n)
{
if (p)
ccrgb[n] = fl_get_slider_value(slider[n]);
fl_mapcolor(OK_I, ccrgb[0], ccrgb[1], ccrgb[2]);
fl_redraw_object(ok_butt);
if (rgbcolor_cb)
{
rgbcolor_cb(ccrgb);
}
}
/****************************************************************
* Pre-defined named colors, mainly from /usr/lib/X11/rgb.txt
*
***************************************************************/
#ifndef RGBTEXT
#define RGBTEXT "/usr/lib/X11/rgb.txt"
#endif
typedef struct
{
int r, g, b;
}
rgbtriple;
/* MAXRGB should not exceed FL_BROWSER_MAXLINE, default 512 */
#define MAXRGB 450
/* make sure it does not happen */
#if (MAXRGB > FL_BROWSER_MAXLINE)
#undef MAXRGB
#define MAXRGB (FL_BROWSER_MAXLINE - 1)
#endif
static rgbtriple rgbs[MAXRGB];
static int ncol;
/***************************************************************
* read the rgb triplets. Only need to do this once, preferably
* after creating the forms
**************************************************************/
static void
read_predefined_col(void)
{
char cname[100]; /* color name */
rgbtriple *p = rgbs;
int r, g, b;
int err, j;
FILE *fp;
if (ncol != 0)
return;
if (!(fp = fopen(RGBTEXT, "r")))
return;
r = b = g = -1;
j = 0;
do
{
p->r = readint(fp);
p->g = readint(fp);
p->b = readint(fp);
fgets(cname, sizeof(cname) - 1, fp);
/* check if anything has gone wrong */
err = (p->r < 0 || p->g < 0 || p->b < 0) || j >= (MAXRGB - 1);
if (err)
continue;
/* there maybe repeats, remove it */
if (r - p->r || g - p->g || b - p->b)
{ /* different */
r = p->r;
g = p->g;
b = p->b;
p++;
j++;
fl_add_browser_line(pcc, de_space_de(cname));
}
}
while (!err);
ncol = j;
fclose(fp);
}
/***************************************************************
* predefc_cb is called by clicking mouse inside the browser,
* we look up the color by examing the line number in browser
**************************************************************/
/*ARGSUSED*/
static void
predefc_cb(FL_OBJECT * ob, long q)
{
int i = fl_get_browser(ob);
rgbtriple *rgb;
--i; /* first line in browser is 1 */
if (i >= 0 && i < ncol)
{
rgb = rgbs + i;
/* handle it by chaning slider value */
set_rgb_slider(rgb->r, rgb->g, rgb->b);
slider_cb(0, 0);
namedcolor = 1;
}
}
/****************************************************************
* Finish up predefined color
****************************************************************/
/* ARGSUSED */
static void
predefc_done(FL_OBJECT * ob, long q)
{
bit_hide_form(predefc);
fl_deselect_browser(pcc);
}
/************************************************************
* select_predefined is called by the RGB form
* Really does not do anything except lending its prototype
************************************************************/
/*ARGSUSED */
static void
select_predefined(FL_OBJECT * ob, long q)
{
read_predefined_col();
bit_show_form(predefc, FL_PLACE_MOUSE, 0, "");
}
/*****************************************************************
*
* END OF RGBCOLOR selection
*
**************************************************************}*/
/**************************************************************
* Select color from a colormap.
*
**************************************************************/
#define CM_CC 301 /* CM_CACEL color */
#define CIOFF 350 /* offset into fl_colormap */
enum
{
CM_RI = CIOFF - 5, CM_GI, CM_BI, CM_GR
};
static int cm_border = 1;
static CMPTR map;
static FL_FORM *cm_form;
static FL_OBJECT *cm_ok, *cm_cancel;
static FL_OBJECT *cm_r, *cm_g, *cm_b, *cm_i, *cm_gr, *bcol[64];
static FL_OBJECT *showmap;
static int cc; /* start of the colormap shown */
static int ci; /* current index in colormap */
static int *cccmap; /* pointer to input array */
static int ccbuf[4]; /* cancel */
static void select_entry(FL_OBJECT *, long);
/*****************************************************************
* Install a colormap for FORM use
*****************************************************************/
static void
set_fl_cmap(CMPTR m)
{
int i = m->colors;
pc_t *red = m->ct[0], *green = m->ct[1], *blue = m->ct[2];
while (--i >= 0)
fl_mapcolor(i + CIOFF, red[i], green[i], blue[i]);
}
/***************************************************************
* Change a single entry i
**************************************************************/
/* Change a single entry in fl colormap */
static void
set_fl_icmap(CMPTR m, int i)
{
if (i >= 0 && i < m->colors)
fl_mapcolor(i + CIOFF, m->ct[0][i], m->ct[1][i], m->ct[2][i]);
}
/********************************************************************
* Show the current selection (marked with a cross) and its index number,
* red, green, blue intensity as well as its equivalent grayscale intensity
*********************************************************************/
static void
show_selection(CMPTR m, int j)
{
int c = cc + CIOFF, gray;
int i;
static int lastci = -1;
/* remove last mark */
if (lastci != j && lastci >= cc && lastci < cc + 64)
{
i = lastci - cc;
fl_set_object_color(bcol[i], c + i, c + i);
fl_set_object_label(bcol[i], "");
}
i = j - cc;
/* show current mark */
if (i >= 0 && i < 64)
{
fl_set_object_color(bcol[i], c + i, c + i);
fl_set_object_label(bcol[i], "@9plus");
fl_set_object_color(cm_ok, c + i, 47);
}
lastci = j;
fl_set_object_label(cm_i, itoa(j + 1));
fl_set_object_label(cm_r, itoa(m->ct[0][j]));
fl_set_object_label(cm_g, itoa(m->ct[1][j]));
fl_set_object_label(cm_b, itoa(m->ct[2][j]));
gray = rgb2gray(m->ct[0][ci], m->ct[1][j], m->ct[2][j]);
fl_set_object_label(cm_gr, itoa(gray));
}
/*******************************************************
* Redraw or remap the colormap. parameter t is the currentlu
* selected entry, in absolute terms, i.e., real map entry
*******************************************************/
static void
init_colors(CMPTR m, int t)
{
int i, c = cc + CIOFF;
fl_freeze_form(cm_form);
for (i = 0; i < 64; i++)
{
fl_set_object_color(bcol[i], c + i, c + i);
fl_set_object_label(bcol[i], "");
}
if (t >= cc && t < cc + 64)
show_selection(m, t);
fl_unfreeze_form(cm_form);
}
/* To set to an entry non-interactively */
static void
set_cmapcolor(int c[])
{
if (c[3] < 0 || c[3] >= imgptr->cmap->colors)
c[3] = imgptr->cmap->colors / 2;
/* show it */
ci = c[3];
cc = 64 * (ci / 64);
/* remap the color */
set_fl_icmap(imgptr->cmap, ci);
/* show it */
init_colors(imgptr->cmap, ci);
/* service color change */
if (cmapcolor_cb)
cmapcolor_cb(c);
}
static void map_done(FL_OBJECT *, long);
static void
hide_cmap_form(void)
{
create_the_forms();
if (cm_form->visible)
map_done(0, 0);
}
/*ARGSUSED*/
static void
draw_cmap_cancel(CMPTR m, int c)
{
fl_mapcolor(CM_CC, m->ct[0][c], m->ct[1][c], m->ct[2][c]);
fl_redraw_object(cm_cancel);
}
/****************************************************
* show current colormap ramp
***************************************************/
static void
show_cmap_all_entries(CMPTR m)
{
int i;
fl_freeze_form(cm_form);
fl_clear_chart(showmap);
for (i = 0; i < m->colors; i++)
fl_add_chart_value(showmap, 1.0, "", CIOFF + i);
fl_unfreeze_form(cm_form);
}
static int
search_map(int k)
{
if (k >= map->colors)
k &= (PCMAX - 1);
return (k >= map->colors) ? -1 : k;
}
/*****************************************************************
* How to handle GL q event in cmap mode
*****************************************************************/
/*ARGSUSED*/
static long
cmap_pick_pix(long dev, short val)
{
int xx, yy, lx = -1, ly = -1, id;
ci_t c;
do
{
WHERE_R2W(xx, yy, win_xo, win_yo);
if (lx - xx || ly - yy)
{
lx = xx;
ly = yy;
show_mouse_position(xx, yy);
rectread(xx, yy, xx, yy, &c);
c &= (MAXCML - 1);
if ((id = search_map(c)) >= 0)
{
cc = 64 * (id / 64);
ci = id;
init_colors(map, id);
/* same as a new selection */
select_entry(0, id - cc);
}
}
}
while (control_down && mouse_down);
fl_qreset();
return 0;
}
static long
cm_fl_event(long dev, short val)
{
long cq = dev;
/* if not meant for this routine, return siliently */
if (!cm_form || !cm_form->visible)
return dev;
switch (dev)
{
case LEFTMOUSE:
case MIDDLEMOUSE:
if (val && control_down)
{
cq = cmap_pick_pix(dev, val);
}
break;
case LEFTCTRLKEY:
case RIGHTCTRLKEY:
if (val)
{
set_cursor(win_id, CUR_S_CROSS);
do
{
if (mouse_down)
cq = cmap_pick_pix(dev, val);
}
while (control_down);
/* control is released, reset cursor */
reset_cursor(win_id);
cq = 0;
}
break;
}
if (cq) /* still not consumed */
cq = cmapcolor_glcb ? cmapcolor_glcb(dev, val) : dev;
return cq;
}
/***********************************************************
* a entry is selected via mouse click.
* MUST not refer to ob, use bcol[i] instead.
************************************************************/
/*ARGSUSED*/
static void
select_entry(FL_OBJECT * ob, long i)
{
if (i < 64 && cc + i < map->colors)
{
if (ci - cc >= 0 && ci - cc < 64)
fl_set_object_label(bcol[ci - cc], "");
ci = cc + i;
}
cccmap[0] = ccbuf[0] = map->ct[0][ci];
cccmap[1] = ccbuf[1] = map->ct[1][ci];
cccmap[2] = ccbuf[2] = map->ct[2][ci];
cccmap[3] = ccbuf[3] = ci;
draw_cmap_cancel(map, ci);
show_selection(map, ci);
/* handle this color change */
if (cmapcolor_cb)
cmapcolor_cb(cccmap);
}
/******************************************************************
* The global function that gets called. After this routine cindex
* must hold a valid value, ie., a value no more than map->colors.
********************************************************************/
int
get_cmapcolor(IPTR im, int clr[], int block)
{
CMPTR m = im->cmap;
int place = block ? FL_PLACE_MOUSE : FL_PLACE_SIZE;
create_the_forms();
if (!(map = m))
return -1;
set_current_color = set_cmapcolor;
/* make a copy of the input color */
ccbuf[0] = clr[0];
ccbuf[1] = clr[1];
ccbuf[2] = clr[2];
/* if bad index on input, choose something reasonable */
if (clr[3] < 0 || clr[3] >= map->colors)
clr[3] = map->colors / 2;
ci = ccbuf[3] = clr[3];
cc = 64 * (ci / 64);
/* alias */
cccmap = clr;
if (block)
{
fl_deactivate_all_forms();
fl_activate_form(rgb_form);
}
if (!cm_form->visible) /* first entry */
{
set_fl_cmap(map);
install_GLQ_handler(cm_fl_event);
show_cmap_all_entries(m);
draw_cmap_cancel(m, ci);
}
init_colors(map, ci);
bit_show_form(cm_form, place, cm_border, "ColorMap");
if (block) /* returns only if OK is pressed */
{
int cmfinish;
short val;
do
{
cmfinish = (fl_do_forms() == FL_EVENT) &&
(bit_qread(&val) == F1KEY && val == 100);
}
while (!cmfinish);
fl_activate_all_forms();
}
return 0;
}
/***************************************************************
* advance or backup 64 entries
***************************************************************/
/* ARGSUSED */
static void
flip_map(FL_OBJECT * ob, long q)
{
if (q == -1)
{ /* backup */
if (cc >= 64)
cc -= 64;
}
else
{
if (cc < map->colors - 64)
cc += 64;
}
init_colors(map, ci);
}
/************************************************************
* finish up
***********************************************************/
/*ARGSUSED*/
static void
map_done(FL_OBJECT * ob, long q)
{
if (cm_form->visible)
{
reset_cursor(win_id);
cmapcolor_cb = 0;
cmapcolor_glcb = 0;
remove_GLQ_handler(cm_fl_event);
bit_hide_form(cm_form);
fl_qenter(F1KEY, 100);
}
}
/****************************************************
* call back routine when cancel button is pressed
* Cancel button is shown only in editmap mode
***************************************************/
/*ARGSUSED*/
static void
map_cancel(FL_OBJECT * ob, long q)
{
ci = cccmap[3] = ccbuf[3];
cc = 64 * (ci / 64);
map->ct[0][ci] = cccmap[0] = ccbuf[0];
map->ct[1][ci] = cccmap[1] = ccbuf[1];
map->ct[2][ci] = cccmap[2] = ccbuf[2];
/* remap the colors */
set_fl_icmap(map, ci);
/* redraw it */
show_selection(map, ci);
/* service this color change */
if (cmapcolor_cb)
cmapcolor_cb(ccbuf);
}
/*****************************************************************
* Edit colormap
*****************************************************************/
static IPTR lim;
/* need two buffers to do the magic */
static currentci[4];
static currentrgb[4];
/************************************************************
* What to do when slider changes
************************************************************/
static void
rgb_change_cb(int c[])
{
ci_t i = currentci[3];
/* change the colormap */
lim->cmap->ct[0][i] = c[0];
lim->cmap->ct[1][i] = c[1];
lim->cmap->ct[2][i] = c[2];
/* change the shown colormap selector entry */
set_fl_icmap(lim->cmap, i);
show_selection(lim->cmap, i);
/* change image as well */
mapcolor(i, c[0], c[1], c[2]);
}
/**********************************************************
* What to do when a new entry is selected
**********************************************************/
static void
ci_change_cb(int c[])
{
set_rgb_slider(c[0], c[1], c[2]);
if (c != currentci)
{
currentci[0] = c[0];
currentci[1] = c[1];
currentci[2] = c[2];
currentci[3] = c[3];
rgb_change_cb(c);
}
}
/*****************************************************************
* Global entry for map editing
******************************************************************/
int
do_editmap(IPTR im)
{
create_the_forms();
if (!IS_CI(im))
{
Bark("EditMap", "%s: not a colormapped image", im->ifile);
return -1;
}
lim = im;
fl_show_object(cm_cancel);
/* what to do if RGB changes */
rgbcolor_cb = rgb_change_cb;
get_RGBcolor(im, currentrgb, 0);
/* OK has no utility, neither does cancel */
fl_deactivate_object(ok_butt);
fl_hide_object_only(cancel);
/*
* since we are editing colormaps, the image is in colormap, do not want
* to have the rgb_fl_event to be active
*/
remove_GLQ_handler(rgb_fl_event);
cmapcolor_cb = ci_change_cb;
get_cmapcolor(im, currentci, 1);
/* hide_rgb_form will try to remove GLQ, it bitches */
install_GLQ_handler(rgb_fl_event);
fl_activate_object(ok_butt);
hide_rgb_form();
/* restore the default */
fl_show_object(cancel);
fl_show_object(cm_cancel);
return 0;
}
/****************************************************************
* main form for cmap color selection
****************************************************************/
static void
create_cmap_form(void)
{
int i, j, k = 18, l;
float dx, dy, x, y, dch = 20;
FL_OBJECT *o, *cm_c[6];
FL_OBJECT *obj;
cm_form = fl_bgn_form(FL_UP_BOX, 266.0, k + 240.0 + dch + 5);
o = fl_add_button(FL_HIDDEN_BUTTON, 0, 0, 240, k + 240, "");
fl_set_call_back(o, help_cb, HELP_COLOR);
/* showmap */
showmap = fl_add_chart(FL_FILLED_CHART, 5, k + 234, 256, dch, "");
fl_set_object_boxtype(showmap, FL_FLAT_BOX);
/* flip backward */
obj = fl_add_button(FL_NB, 10.0, k + 50.0, 35.0, 178.0, "@4");
fl_set_object_lcol(obj, 3);
fl_set_call_back(obj, flip_map, -1);
dx = dy = 22.0;
for (i = 0; i < 8; i++)
{
for (j = 0; j < 8; j++)
{
x = 45.0 + dx * j;
y = k + 205.0 - dy * i;
l = 8 * i + j;
bcol[l] = obj = fl_add_button(FL_NB, x, y, dx, dy, "");
fl_set_object_boxtype(obj, FL_BORDER_BOX);
fl_set_object_lcol(obj, 7);
fl_set_call_back(obj, select_entry, l);
}
}
/* flip forward */
obj = fl_add_button(FL_NB, 45 + dx * 8, k + 50.0, 35.0, 178.0, "@6");
fl_set_object_lcol(obj, 3);
fl_set_call_back(obj, flip_map, 1);
cm_cancel = obj = fl_add_button(FL_NB, 20.0, 10.0, 90.0, 30.0, "Cancel");
fl_set_call_back(obj, map_cancel, 0);
fl_set_object_color(obj, CM_CC, FL_RED);
fl_set_object_lcol(obj, FL_GREEN);
cm_ok = obj = fl_add_button(FL_NB, 150.0, 10.0, 90.0, 30.0, "OK");
fl_set_call_back(obj, map_done, 0);
fl_set_object_lcol(cm_ok, FL_MAGENTA);
fl_set_object_lstyle(cm_ok, FL_BOLD_STYLE);
/* the following four are the colorindex, red, green, blue */
dx = 47.0;
dy = 20.0;
for (x = 13, y = 45, i = 0; i < 5; i++, x += dx)
{
cm_c[i] = o = fl_add_text(FL_NORMAL_TEXT, x, y, dx, dy, "");
fl_set_object_boxtype(o, FL_BORDER_BOX);
fl_set_object_lstyle(o, FL_BOLD_STYLE);
fl_set_object_align(o, FL_ALIGN_CENTER);
}
cm_i = cm_c[0];
fl_set_object_lcol(cm_i, 0);
cm_r = cm_c[1];
fl_set_object_lcol(cm_r, 7);
cm_g = cm_c[2];
fl_set_object_lcol(cm_g, 0);
cm_b = cm_c[3];
fl_set_object_lcol(cm_b, 7);
cm_gr = cm_c[4];
fl_set_object_lcol(cm_gr, 0);
fl_end_form();
fl_mapcolor(CM_RI, 255, 0, 0);
fl_mapcolor(CM_GI, 0, 255, 0);
fl_mapcolor(CM_BI, 0, 0, 255);
fl_mapcolor(CM_GR, 200, 200, 200);
fl_set_object_color(cm_r, CM_RI, CM_RI);
fl_set_object_color(cm_g, CM_GI, CM_GI);
fl_set_object_color(cm_b, CM_BI, CM_BI);
fl_set_object_color(cm_gr, CM_GR, CM_GR);
/* hide cancel by default */
fl_hide_object(cm_cancel);
}
/***************************************************************
* FORMS for predefined colors: a browser & a button
**************************************************************/
static void
create_form_predefc(void)
{
FL_OBJECT *obj;
predefc = fl_bgn_form(FL_NO_BOX, 195.0, 255.0);
obj = fl_add_box(FL_UP_BOX, 0.0, 0.0, 195.0, 255.0, "");
pcc = obj = fl_add_browser(FL_HBR, 20.0, 40.0, 140.0, 200.0, "");
fl_set_object_boxtype(obj, FL_SHADOW_BOX);
fl_set_call_back(obj, predefc_cb, 0);
fl_set_browser_fontsize(pcc, 10.0);
obj = fl_add_button(FL_NB, 120.0, 10.0, 60.0, 25.0, "Done");
fl_set_object_lsize(obj, 10.0);
fl_set_call_back(obj, predefc_done, 0);
fl_end_form();
/* load the color definations */
}
/****************************************************************
* Main RGB form
*****************************************************************/
static void
create_rgb_form(void)
{
FL_OBJECT *obj;
float x = 10, dx = 320, dy = 30.0;
int i;
rgb_form = fl_bgn_form(FL_NO_BOX, 400.0, 170.0);
obj = fl_add_box(FL_UP_BOX, 0.0, 0.0, 400.0, 170.0, "");
/* three mixers */
slider[0] = obj = fl_add_valslider(FL_HFS, x, 10.0, dx, dy, "");
fl_set_object_color(obj, 47, FL_RED);
fl_set_object_lstyle(obj, FL_BOLD_STYLE);
fl_set_call_back(obj, slider_cb, 0);
slider[1] = obj = fl_add_valslider(FL_HFS, x, 50.0, dx, dy, "");
fl_set_object_color(obj, 47, FL_GREEN);
fl_set_object_lstyle(obj, FL_BOLD_STYLE);
fl_set_call_back(obj, slider_cb, 1);
slider[2] = obj = fl_add_valslider(FL_HFS, x, 90.0, dx, dy, "");
fl_set_object_color(obj, 47, FL_BLUE);
fl_set_object_lstyle(obj, FL_BOLD_STYLE);
fl_set_call_back(obj, slider_cb, 2);
ok_butt = obj = fl_add_button(FL_NB, 340.0, 10.0, 50.0, 110.0, "OK");
fl_set_object_lstyle(obj, FL_BOLD_STYLE);
fl_set_object_color(obj, OK_I, 47);
fl_set_object_lcol(obj, FL_MAGENTA);
fl_set_call_back(obj, ok_cb, 0);
dx = 100.0;
dy = 30.0;
obj = fl_add_button(FL_NB, 20.0, 130.0, dx, dy, "ColorHelp");
fl_set_call_back(obj, help_cb, HELP_COLOR);
fl_set_object_lsize(obj, 10.0);
obj = fl_add_button(FL_NB, 20 + dx, 130, dx, dy, "PreDefCol");
fl_set_call_back(obj, select_predefined, 0);
fl_set_object_lsize(obj, 10.0);
cancel = obj = fl_add_button(FL_NB, 20 + 2 * dx, 130.0, dx, dy, "Cancel");
fl_set_object_color(obj, CAN_I, 47);
fl_set_object_lsize(obj, 10.0);
fl_set_object_lcol(obj, FL_CYAN);
fl_set_call_back(obj, cancel_cb, 0);
fl_end_form();
/* default properties */
for (i = 0; i < 3; i++)
{
fl_set_slider_bounds(slider[i], 0.0, PCMAXV);
fl_set_slider_value(slider[i], 0.0);
fl_set_slider_precision(slider[i], 0);
fl_set_slider_step(slider[i], 1.0);
}
}
static void
create_the_forms(void)
{
static int fmade;
if (!fmade)
{
create_rgb_form();
create_form_predefc();
create_cmap_form();
fmade = 1;
}
}